package cn.admin.remoting.serialize.impl;

import cn.admin.remoting.Remoting;
import cn.admin.remoting.impl.ConnectionRequest;
import cn.admin.remoting.serialize.CustomSerialization;
import cn.admin.remoting.serialize.DefaultSerialization;
import cn.admin.remoting.serialize.SerializationUtil;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class ConnRequestSerialization implements CustomSerialization<ConnectionRequest> {

    private static final int IDX_DIRECTION = 3;
    private static final int IDX_APPTYPE = 9;
    private static final CustomSerialization<Object> defaultSerial = new DefaultSerialization();

    private static CustomSerialization<Object> getSerial(String type) {
        Remoting.serialUtil();
        CustomSerialization<Object> result = SerializationUtil.getCustom(type);
        if (null == result) {
            result = defaultSerial;
        }
        return result;
    }

    @Override
    public void serialize(ConnectionRequest request, byte protocol, OutputStream out) throws IOException {
        Object appRequest = request.getAppRequest();
        String appType = null != appRequest ? appRequest.getClass().getName() : "";
        SliceOutputStream bout = (SliceOutputStream) out;
        byte[] header = new byte[]{13,0,protocol,request.getDirection(),0};
        bout.write(header);
        bout.skipInt("connLength");
        bout.write((byte)appType.length());
        bout.skipInt("appLength");
        int curSize = bout.size();
        defaultSerial.serialize(request, protocol, bout);
        bout.writeSkippedInt("connLength", bout.size() - curSize);
        bout.write(appType.getBytes());
        curSize = bout.size();
        getSerial(appType).serialize(appRequest, protocol, bout);
        bout.writeSkippedInt("appLength", bout.size() - curSize);
    }

    @Override
    public ConnectionRequest deserialize(InputStream input, byte protocol) throws IOException {
        ConnectionRequest request = null;

        try {
            byte[] headers = new byte[14];
            input.read(headers);
            byte direction = headers[IDX_DIRECTION];
            int appTypeLen = headers[IDX_APPTYPE] & 255;
            request = (ConnectionRequest) defaultSerial.deserialize(input,protocol);
            request.setDirection(direction);
            request.setSerializeProtocol(protocol);
            if (0 == appTypeLen) {
                request.setSerializeProtocol(protocol);
                request.setAppRequest(null);
                return request;
            } else {
                byte[] tmp = new byte[appTypeLen];
                input.read(tmp);
                String appType = new String(tmp);
                Object appRequest = getSerial(appType).deserialize(input, protocol);
                request.setSerializeProtocol(protocol);
                request.setAppRequest(appRequest);
                return request;
            }
        } catch (IOException e) {
            throw new DeserializeException(e,request);
        }
    }
}
